#include "Matrix.hpp"
#include "Time.hpp"
#include "mm_mkl.hpp"
#include "mm_v1.hpp"
#include "mm_v10.hpp"
#include "mm_v2.hpp"
#include "mm_v3.hpp"
#include "mm_v4.hpp"
#include "mm_v5.hpp"
#include "mm_v6.hpp"
#include "mm_v7.hpp"
#include "mm_v8.hpp"
#include "mm_v9.hpp"

int main() {
    const int kSize = 100;
    const int kSize2 = kSize + 1;
    double *a = new double[kSize * kSize2];
    double *b = new double[kSize2 * kSize];
    double *c = new double[kSize * kSize];
    double *d = new double[kSize * kSize];
    random_fill(a, kSize * kSize2);
    random_fill(b, kSize2 * kSize);
    zero_fill(d, kSize * kSize);
    mm_v1(kSize, kSize, kSize2, a, kSize, b, kSize2, d, kSize);
#define MM_CHECK(gemm_vx)                                                      \
    zero_fill(c, kSize *kSize);                                                \
    gemm_vx(kSize, kSize, kSize2, a, kSize, b, kSize2, c, kSize);              \
    std::cout << #gemm_vx << " ";                                              \
    if (equal(c, d, kSize * kSize)) {                                          \
        std::cout << "\tpassed ";                                              \
    } else {                                                                   \
        std::cout << "\tfailed ";                                              \
    }                                                                          \
    std::cout << get_execution_time(std::bind(gemm_vx, kSize, kSize, kSize2,   \
                                              a, kSize, b, kSize2, c, kSize))  \
              << " ms" << std::endl;

    MM_CHECK(mm_v1);
    MM_CHECK(mm_v2);
    MM_CHECK(mm_v3);
    MM_CHECK(mm_v4);
    MM_CHECK(mm_v5);
    MM_CHECK(mm_v6);
    MM_CHECK(mm_v7);
    MM_CHECK(mm_v8);
    MM_CHECK(mm_v9);
    MM_CHECK(mm_v10);
    mkl_set_num_threads(1);
    MM_CHECK(mm_mkl);

#undef MM_CHECK
    delete[] a;
    delete[] b;
    delete[] c;
    delete[] d;
    return 0;
}
